﻿namespace EFS.RC.ClientPlatform
{
	public class Platform : EFS.Common.Async.AsyncRoot
	{
		#region Locals

		// instance
		private static EFS.RC.ClientPlatform.Platform instance = null;

		// sync access
		private static object syncAccess = new object();

		// Collaboration platform
		private Microsoft.Rtc.Collaboration.CollaborationPlatform collaborationPlatform = null;

		// End point
		private EFS.RC.ClientPlatform.EndPoint endPoint = null;

		/// <summary>
		/// Status
		/// </summary>
		public enum PlatformStatus { Idle, Started, Terminated }

		// Status
		private PlatformStatus status = PlatformStatus.Idle;

		#endregion // Locals

		#region Delgates

		/// <summary>
		/// Shut down event delegate
		/// </summary>
		public delegate void Terminated();

		/// <summary>
		/// Terminated session delegate registrar
		/// </summary>
		public Terminated OnTerminated = null;

		/// <summary>
		/// Shut down event delegate
		/// </summary>
		public delegate void Established();

		/// <summary>
		/// Established session delegate registrar
		/// </summary>
		public Established OnEstablished = null;

		#endregion

		#region Constructor

		/// <summary>
		/// Private constructor
		/// </summary>
		private Platform(){ }

		#endregion

		#region Usage

		/// <summary>
		/// Our platform
		/// </summary>
		public static EFS.RC.ClientPlatform.Platform Instance 
		{ 
			get 
			{
				// check
				if (null == instance)
				{
					instance = new Platform();
				}

				// get
				return instance;
			}
		}

		/// Get status
		public PlatformStatus Status
		{
			get { return status; }
		}

		/// <summary>
		/// Get collaboration
		/// </summary>
		internal Microsoft.Rtc.Collaboration.CollaborationPlatform CollaborationPlatform
		{
			get { return collaborationPlatform; }
		}

		/// <summary>
		/// Get end point
		/// </summary>
		public EFS.RC.ClientPlatform.EndPoint EndPoint
		{
			get 
			{
				// check
				if (null == endPoint)
				{
					throw new System.InvalidOperationException("End point not started");
				}

				// get
				return endPoint; 
			}
		}

		/// <summary>
		/// Describe this object
		/// </summary>
		/// <returns></returns>
		public override System.String Describe()
		{
			return "EFS.RC.ClientPlatform.Platform";
		}

		/// <summary>
		/// Begin platform startup
		/// </summary>
		public EFS.Common.Async.AsyncProcess BeginStartup()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginStartup", this);

			// start-up
			return BeginAsyncProcess2(Startup, OnStartupComplete);
		}

		/// <summary>
		/// Begin sutdown
		/// </summary>
		public EFS.Common.Async.AsyncProcess BeginShutdown()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginShutdown", this);

			// shutdown
			return BeginAsyncProcess2(Shutdown, OnShutdownComplete);
		}

		#endregion // Instance & start-up

		#region Startup

		/// <summary>
		/// Platform startup
		/// </summary>
		private void Startup()
		{
			// log
			EFS.EventLog.Log.LogInfo("Startup", this);

			// lock access
			lock (syncAccess)
			{
				if (status != PlatformStatus.Idle)
				{
					throw new System.InvalidOperationException("Only Idle Platform can be started");
				}

				// started
				status = PlatformStatus.Started;
			}

			// make settings
			// Initalize and startup the platform.
			Microsoft.Rtc.Collaboration.ClientPlatformSettings clientPlatformSettings =
				new Microsoft.Rtc.Collaboration.ClientPlatformSettings("EFS.RC.ClientPlatform", Microsoft.Rtc.Signaling.SipTransportType.Tls);
			collaborationPlatform = new Microsoft.Rtc.Collaboration.CollaborationPlatform(clientPlatformSettings);

			// start
			collaborationPlatform.BeginStartup(OnCollaborationPlatformStartupComplete, null);
		}

		/// <summary>
		/// Start-up complete
		/// </summary>
		/// <param name="ar"></param>
		private void OnStartupComplete(EFS.Common.Async.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnStartupComplete", this);

			try
			{
				// check
				ap.Throw();
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);

				// close
				BeginShutdown();
			}
		}

		/// <summary>
		/// Complete start
		/// </summary>
		/// <param name="ar"></param>
		private void OnCollaborationPlatformStartupComplete(System.IAsyncResult ar)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnCollaborationPlatformStartupComplete", this);

			try
			{
				// end
				collaborationPlatform.EndStartup(ar);

				// make end point
				endPoint = new EFS.RC.ClientPlatform.EndPoint();
				endPoint.OnEstablished += OnEndPointEstablished;
				endPoint.OnTerminated += OnEndPointTerminated;

				// start end point
				endPoint.BeginStartup();
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);

				// shutdown
				BeginShutdown();
			}
		}

		/// <summary>
		/// Called by end point when established
		/// </summary>
		private void OnEndPointEstablished()
		{
			try
			{
				// check
				if (null != OnEstablished)
				{
					// call 
					OnEstablished();
				}
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);

				// shutdown
				BeginShutdown();
			}
		}

		/// <summary>
		/// Called by end point when terminated
		/// </summary>
		private void OnEndPointTerminated()
		{
			// shut down
			BeginShutdown();
		}

		#endregion // Startup

		#region Runtime

		/// <summary>
		/// Unhandled exception
		/// </summary>
		/// <param name="ex"></param>
		protected override void OnException(System.Exception ex)
		{
			// check
			EFS.Common.Verify.Reference(ex, "ex");

			// log
			EFS.EventLog.Log.LogException(ex, this);

			// close
			BeginShutdown();
		}

		#endregion

		#region Shutdown

		/// <summary>
		/// Shut down
		/// </summary>
		private void Shutdown()
		{
			// log
			EFS.EventLog.Log.LogInfo("Shutdown", this);

			// lock local acess
			lock (syncAccess)
			{
				// check already terminated
				if (status != PlatformStatus.Terminated)
				{
					// set terinated
					status = PlatformStatus.Terminated;
				}
				else
				{
					// already terminated
					return;
				}
			}

			// shutdown end point
			if (null != endPoint)
			{
				// remove delegates
				endPoint.OnEstablished -= OnEndPointEstablished;
				endPoint.OnTerminated -= OnEndPointTerminated;

				// terminate
				if (endPoint.Status != EndPoint.EndPointStatus.Terminated)
				{
					endPoint.BeginShutdown();
				}
			}

			// shutdown platform
			if (null != collaborationPlatform)
			{
				// shut down platform
				System.IAsyncResult arShutDown = collaborationPlatform.BeginShutdown(OnCollabPlatformShutdownComplete, null);

				// wait for it
				collaborationPlatform.EndShutdown(arShutDown);
			}
		}

		/// <summary>
		/// shut down complete
		/// </summary>
		/// <param name="ap"></param>
		private void OnShutdownComplete(EFS.Common.Async.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnShutdownComplete", this);

			try
			{
				// check delegate
				if (null != OnTerminated)
				{
					// call
					OnTerminated();
				}
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		/// <summary>
		/// Shut down complete
		/// </summary>
		/// <param name="ar"></param>
		void OnCollabPlatformShutdownComplete(System.IAsyncResult ar)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnCollabPlatformShutdownComplete", this);
		}

		#endregion // Shutdown
	}
}
